﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameModel : ISSActionCallback {
    Hashtable ht;
    GameObject[] roles;
    GameObject boat;
    GameObject[] banks;

    Vector3[] p_roles;
    float[] tx_boat;
    Vector3[] rp_boatroles;

    int cur_boatside;

    /* 0 for no animation, 1 for jumping, 2 for rowing */
    int animating_state;
    /* 0 for in-game, 1 for lose, 2 for win */
    int game_state;

    SSActionManager action_manager;
    
    public GameModel() {
        ht = new Hashtable();
        roles = new GameObject[14];
        banks = new GameObject[2];
        p_roles = new Vector3[6];
        tx_boat = new float[2];
        rp_boatroles = new Vector3[2];
    }
    public void SetActionManager(SSActionManager manager) {
        this.action_manager = manager;
    }
    public void AddObject(string name, GameObject gameObject) {
        ht.Add(name, gameObject);
    }
    public void Init() {
        for (int i = 0; i < roles.Length; ++i) {
            roles[i] = null;
        }
        boat = (GameObject)ht["Boat"];
        for (int i = 0; i < 3; ++i) {
            roles[6 + i] = (GameObject)ht["Priest" + i];
            roles[9 + i] = (GameObject)ht["Devil" + i];
        }
        banks[0] = (GameObject)ht["BankLeft"];
        banks[1] = (GameObject)ht["BankRight"];

        banks[0].transform.position = new Vector3(-10, 0, 0);
        banks[1].transform.position = -banks[0].transform.position;

        float y_role = (banks[1].transform.lossyScale.y + roles[6].transform.lossyScale.y) * 0.5f;
        float tem = (banks[1].transform.lossyScale.x - 6 * roles[6].transform.lossyScale.x) / 7.0f;
        float x_role = banks[1].transform.position.x - 2.5f * (tem + roles[6].transform.lossyScale.x);
        for (int i = 0; i < 6; ++i) {
            p_roles[i] = new Vector3(x_role, y_role, 0.0f);
            x_role += tem + roles[6].transform.lossyScale.x;
            roles[6 + i].transform.position = p_roles[i];
            Role role = roles[6 + i].GetComponent<Role>();
            role.Init();
            role.cur_pos = 6 + i;
        }

        tx_boat[1] = (banks[1].transform.lossyScale.x - boat.transform.lossyScale.x) * 0.5f;
        tx_boat[0] = -tx_boat[1];
        float t1 = banks[1].transform.lossyScale.y - boat.transform.lossyScale.y;
        boat.transform.position = new Vector3(tx_boat[1], t1 * -0.4f, 0);

        rp_boatroles[1].y = rp_boatroles[0].y = (boat.transform.lossyScale.y + roles[6].transform.lossyScale.y) * 0.5f;
        tem = (boat.transform.lossyScale.x - roles[6].transform.lossyScale.x * 2) / 3.0f;
        rp_boatroles[1].x = (tem + roles[6].transform.lossyScale.x) * 0.5f;
        rp_boatroles[0].x = -rp_boatroles[1].x;
        rp_boatroles[1].z = rp_boatroles[0].z = 0;

        cur_boatside = 1;

        animating_state = 0;
        game_state = 0;

        action_manager.Clear();
    }

    public void Switch(GameObject obj) {
        Role jumping_role = obj.GetComponent<Role>();
        int idx;
        Vector3 des;
        if (jumping_role.cur_side != -1) {
            for (idx = 12; idx < 14; ++idx) {
                if (roles[idx] == null) {
                    break;
                }
            }
            if (idx == 14) {
                jumping_role = null;
                return;
            }
            jumping_role.cur_side = -1;
            des = boat.transform.position + rp_boatroles[idx - 12];
        }
        else {
            int tem = ((cur_boatside << 1) | jumping_role.type);
            for (idx = tem * 3; idx < (tem + 1) * 3; ++idx) {
                if (roles[idx] == null) {
                    break;
                }
            }
            jumping_role.cur_side = cur_boatside;
            des = p_roles[idx % 6];
            des.x *= (jumping_role.cur_side == 1? 1: -1);
        }
        roles[jumping_role.cur_pos] = null;
        jumping_role.cur_pos = idx;
        roles[jumping_role.cur_pos] = obj;

        float height = 3.0f, speed = 10.0f;
        SSMoveToAction[] actions = new SSMoveToAction[3];
        for (int i = 0; i < 3; ++i) {
            actions[i] = SSMoveToAction.GetSSAction();
        }
        Vector3 pos = obj.transform.position;
        pos.y = height;
        actions[0].Init(pos, speed, obj);
        pos.x = des.x;
        actions[1].Init(pos, speed, obj);
        actions[2].Init(des, speed, obj);
        SSSequenceAction action = SSSequenceAction.GetSSAction();
        action.Init(actions, 1, this);
        action_manager.RunAction(action);

        animating_state = 1;
    }

    public void SetOff() {
        if (roles[12] == null && roles[13] == null) {
            return;
        }
        Vector3 dpos = new Vector3(-boat.transform.position.x * 2, 0, 0);
        float speed = 3.0f;
        float[] coe = new float[2]{0.3f, 1.0f};
        SSParallelAction[] actionPar = new SSParallelAction[2];
        for (int i = 0; i < 2; ++i) {
            actionPar[i] = SSParallelAction.GetSSAction();
            List<SSAction> actions = new List<SSAction>();
            SSMoveToAction act_boat = SSMoveToAction.GetSSAction();
            act_boat.Init(boat.transform.position + dpos * coe[i], speed, boat);
            actions.Add(act_boat);
            for (int j = 12; j < 14; ++j) {
                if (roles[j] == null) {
                    continue;
                }
                SSMoveToAction act_role = SSMoveToAction.GetSSAction();
                act_role.Init(roles[j].transform.position + dpos * coe[i], speed, roles[j]);
                actions.Add(act_role);
            }
            actionPar[i].Init(actions, 2 + i, this);
        }
        SSSequenceAction action = SSSequenceAction.GetSSAction();
        action.Init(actionPar);
        action_manager.RunAction(action);

        animating_state = 2;
        cur_boatside ^= 1;
    }

    public void Update(float dt) {
    }

    public bool IsAnimating() {
        return animating_state > 0;
    }

    public int GetGameState() {
        return game_state;
    }

    bool CheckGameover(bool isArriving) {
        int[] tnum = new int[2];
        int startindex = 6 * (cur_boatside ^ (isArriving? 0: 1));
        for (int i = 0; i < 6; ++i) {
            tnum[i / 3] += (roles[startindex + i] == null? 0: 1);
        }
        if (isArriving) {
            for (int i = 12; i < 14; ++i) {
                if (roles[i] != null) {
                    if (roles[i].name.StartsWith("Priest")) {
                        ++tnum[0];
                    }
                    else {
                        ++tnum[1];
                    }
                }
            }
        }
        return tnum[0] != 0 && tnum[0] < tnum[1];
    }

    bool CheckWin() {
        for (int i = 0; i < 6; ++i) {
            if (roles[i] == null) {
                return false;
            }
        }
        return true;
    }

    public void SSActionEvent(SSAction source, SSActionEventType events, int identifier, Object param) {
        switch (identifier) {
        case 1: // Switch a role
            animating_state = 0;
            if (CheckWin()) {
                game_state = 2;
            }
            break;
        case 2: // Leaving
            if (CheckGameover(false)) {
                game_state = 1;
                action_manager.Clear();
            }
            break;
        case 3: // Arriving
            animating_state = 0;
            if (CheckGameover(true)) {
                game_state = 1;
                action_manager.Clear();
            }
            break;
        }
    }
}
